package uk.co.q3c.deplan.client.domain.task;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import uk.co.q3c.deplan.client.domain.DomainObject;
import uk.co.q3c.deplan.client.domain.dag.ChangeInvalidException;
import uk.co.q3c.deplan.client.domain.dag.CycleDetectedException;
import uk.co.q3c.deplan.client.domain.resource.PersistenceReferenceException;

import com.googlecode.objectify.Key;

/**
 * @see Task
 * @see BaseTask
 * @see Project
 * @see BaseTask
 * @author DSowerby 22 Jun 2008 23:20:17
 * 
 */
public interface Task extends DomainObject {

	/**
	 * Adds the supplied predecessor. Calls with null are logged, but not acted on. Calls with duplicate predecessors are ignored. A
	 * predecessor cannot be a summary task.Also calls the {@link #addSuccessor(this)} of the predecessor to form a bi-directional link
	 * 
	 * @param predecessor
	 *            the predecessor to be added
	 * @throws PersistenceReferenceException
	 * @throws CycleDetectedException
	 */
	public abstract void addPredecessor(Task predecessor) throws PersistenceReferenceException;

	/**
	 * @see #addSuccessor(Task)
	 * @param successor
	 * @throws PersistenceReferenceException
	 */
	public void addSuccessor(Task successor) throws PersistenceReferenceException;

	/**
	 * Clears any levelling related fields
	 */
	public abstract void clearLevelling();

	/**
	 * @see BaseTask#DAGLabel()
	 * @return
	 */
	String DAGLabel();

	/**
	 * Returns the plannedFinish date of this task, or date of 0 if none set
	 * 
	 * @return
	 * @throws PersistenceReferenceException
	 */
	public abstract Date finish() throws PersistenceReferenceException;

	/**
	 * Returns the plannedFinish date in milliseconds of this task, or date of 0 if none set
	 * 
	 * @return
	 * @throws PersistenceReferenceException
	 */

	public abstract long finishTime() throws PersistenceReferenceException;

	/**
	 * Fires a property change event with property name "_test". Used for testing
	 */
	public abstract void fireTestProperty();

	public abstract double getDuration();

	Key<? extends Task> getKey() throws PersistenceReferenceException;

	public String getName();

	public abstract BaseTask getParentTask() throws PersistenceReferenceException;

	public Key<BaseTask> getParentTaskKey() throws PersistenceReferenceException;

	/**
	 * Returns a copy of predecessors - the list is a copy but the contained tasks are the same references in the copy as in the original
	 * 
	 * @return
	 * @throws PersistenceReferenceException
	 */
	public abstract ArrayList<Task> getPredecessors() throws PersistenceReferenceException;

	/**
	 * Returns current priority, unless it is 0. If 0, and parent is set, then the parent's priority is returned instead.
	 * 
	 * @return
	 */
	public abstract int getPriority();

	public abstract String getSpecification();

	// public abstract void addPropertyChangeListener(String string, PropertyChangeListener propertyChangeListener);
	//
	// /**
	// * A standard listener add except that for summary tasks this is overridden to cascade the call to subtasks
	// */
	// public abstract void addPropertyChangeListener(PropertyChangeListener propertyChangeListener);

	/**
	 * @return Date
	 */
	public abstract Date getStartRemaining();

	public abstract List<Task> getSuccessors() throws PersistenceReferenceException;

	/**
	 * @return
	 */
	Date getTargetFinishDate();

	/**
	 * @return
	 */
	Date getTargetStartDate();

	public long getTaskId();

	/**
	 * Temporary id used during import
	 * 
	 * @return
	 */
	public int getTempId();

	public int getWorkDone();

	int getWorkRemaining();

	/**
	 * Returns true if this task has an ancestor matching <code>task</code>
	 * 
	 * @param task
	 * @return
	 * @throws PersistenceReferenceException
	 */

	public boolean hasAncestor(Task task) throws PersistenceReferenceException;

	public abstract boolean hasDependencies();

	public boolean hasPredecessor(Task pred);

	boolean hasPredecessors();

	public boolean hasSubTasks();

	public boolean hasSuccessor(Task succ);

	public abstract boolean isComplete();

	public abstract boolean isFullyAllocated();

	public boolean isProject();

	boolean isResourceDriven();

	public boolean isService();

	public abstract long lastPredecessorFinish() throws PersistenceReferenceException;

	public abstract void moveDependenciesTo(Task targetTask) throws PersistenceReferenceException;

	/**
	 * When a summary task is discarded, it is required that its sub tasks are also discarded. This method provides a way to do that without
	 * causing a child to drop its reference to its parent, which a call to {@link PersistedObject#setDiscarded(boolean)} would do. It is
	 * expected that this method will only be called by this task's parent.
	 * 
	 * @throws PersistenceReferenceException
	 */
	public void parentDiscarded(boolean discarded, Date date) throws PersistenceReferenceException;

	/**
	 * @param proposedSuccessor
	 * @return
	 * @throws PersistenceReferenceException
	 */
	public abstract boolean predecessorChainContains(Task proposedSuccessor) throws PersistenceReferenceException;

	/**
	 * This is a DIRECT reference to predecessors, not a copy. Use with care.
	 * 
	 * @return
	 * @throws PersistenceReferenceException
	 */
	public abstract List<Task> predecessors() throws PersistenceReferenceException;

	/**
	 * returns predecessors as a comma separated string representation
	 * 
	 * @return predecessors as a comma separated string representation
	 * @throws PersistenceReferenceException
	 */
	public abstract String predecessorsString() throws PersistenceReferenceException;

	public abstract String qualifiedName();

	/**
	 * @param predecessor
	 */
	void removePredecessor(Task predecessor);

	/**
	 * @param successor
	 */
	void removeSuccessor(Task successor);

	public abstract void reportStatus(TaskStatusReport taskStatusReport) throws PersistenceReferenceException;

	public Task root() throws PersistenceReferenceException;

	public abstract void setFixedDuration(boolean value);

	void setKeyId(Long id);

	public void setName(String s);

	/**
	 * If this parentTask has this object as an ancestor this call is ignored, otherwise the parentTask is set. If this parent task is
	 * currently a predecessor, that dependency is removed
	 * 
	 * @param newParentTask
	 * @throws CycleDetectedException
	 * @throws ChangeInvalidException
	 * @throws PersistenceReferenceException
	 */
	public abstract void setParentTask(BaseTask newParentTask) throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException;

	public abstract void setPriority(int priority) throws PersistenceReferenceException;

	public void setProject();

	public abstract void setSpecification(String description);

	/**
	 * Set the date on which remaining work or activity will commence. Usually only called by levelling routine
	 * 
	 * @param date
	 */
	public abstract void setStartRemaining(Date date);

	/**
	 * @param targetDate
	 */
	void setTargetFinishDate(Date targetDate);

	/**
	 * @param targetDate
	 */
	void setTargetStartDate(Date targetDate);

	public void setTempId(int id);

	public void setWorkDone(int wd);

	void setWorkRemaining(int workRemaining);

	/**
	 * Returns the start date of this task, or date of 0 if none set
	 * 
	 * @return
	 * @throws PersistenceReferenceException
	 */
	public abstract Date start() throws PersistenceReferenceException;

	/**
	 * Returns the start date in milliseconds of this task, or date of 0 if none set
	 * 
	 * @return
	 * @throws PersistenceReferenceException
	 */
	public abstract long startTime() throws PersistenceReferenceException;

	/**
	 * This is a DIRECT reference to successors, not a copy. Use with care.
	 * 
	 * @return
	 * @throws PersistenceReferenceException
	 */
	public abstract List<Task> successors() throws PersistenceReferenceException;

	/**
	 * returns successors as a comma separated string representation
	 * 
	 * @return successors as a comma separated string representation
	 * @throws PersistenceReferenceException
	 */
	public abstract String successorsString() throws PersistenceReferenceException;

	/**
	 * Returns the total number of tasks in the hierarchy including this one
	 * 
	 * @return
	 * @throws PersistenceReferenceException
	 */
	public abstract int taskCount() throws PersistenceReferenceException;

	public abstract int getWorkAllocated();

	public abstract void setWorkAllocated(int wa);

	Date getActualStart();

	Date getActualFinish();

	public abstract void setActualStart(Date actualStart);

	void setActualFinish(Date actualFinish);

	public abstract Date getPlannedFinish() throws PersistenceReferenceException;

	public abstract void setPlannedFinish(Date plannedFinish);

	public abstract void setParentPriority(int priority);

	boolean isUsingParentPriority();

	void setUsingParentPriority(boolean inheritParentPriority);

}